﻿#include "MathTools.h"
#include <QTime>
#include <QFontMetricsF>

BEGIN_NAMESPACE_CIQTEK

MathTools::MathTools()
{
}

MathTools::~MathTools()
{
}

float MathTools::generateRandomNumber()
{
    qsrand(QTime(0,0,0).secsTo(QTime::currentTime()));
    return float(qrand() % 1000000) / 1000000;
}

QPointF MathTools::pointRotateTransform(double x0, double y0, double x, double y, double r, bool isDegree)
{
    if(isDegree)
    {
        r = qDegreesToRadians(r);
    }

    double cosVal = qCos(r);
    double sinVal = qSin(r);

    return QPointF((x0*cosVal - y0*sinVal + x - x*cosVal + y*sinVal), (x0*sinVal + y0*cosVal + y - x*sinVal - y*cosVal));
}

double MathTools::distanceFromPointToLine(QPointF point, QVector<QPointF> vector)
{
    if(vector.size() != 2)
    {
        return 0;
    }
    QPointF a = vector[0];
    QPointF b = vector[1];

    double cross = (b.rx() - a.rx()) * (point.rx() - a.rx()) + (b.ry() - a.ry()) * (point.ry() - a.ry());
    if(cross <= 0)
    {
        return distanceFromTwoPoint(a, point);
    }

    double ab2 = (b.rx() - a.rx()) * (b.rx() - a.rx()) + (b.ry() - a.ry()) * (b.ry() - a.ry());

    if(cross >= ab2)
    {
        return distanceFromTwoPoint(b, point);
    }

    double r = cross / ab2;

    QPointF abCenter = QPointF(a.rx() + (b.rx() - a.rx()) * r, a.ry() + (b.ry() - a.ry()) * r);

    return distanceFromTwoPoint(point, abCenter);
}

double MathTools::distanceFromPointToStraightLine(QPointF point, QVector<QPointF> vector)
{
    if(vector.size() != 2)
    {
        return 0;
    }
    QPointF p1 = vector[0];
    QPointF p2 = vector[1];

    double a = distanceFromTwoPoint(p1, p2);
    double b = distanceFromTwoPoint(p1, point);
    double c = distanceFromTwoPoint(point, p2);

    double S = 1.0/4.0 * qSqrt((a+b+c) * (a+b-c) * (a+c-b) * (b+c-a));
    double dis = S * 2.0 / a;
    return dis;
}

double MathTools::distanceFromTwoPoint(QPointF p1, QPointF p2)
{
    double dx = qAbs(p1.rx() - p2.rx());
    double dy = qAbs(p1.ry() - p2.ry());
    return qSqrt(dx * dx + dy * dy);
}

double MathTools::getAngleByVector(QVector<QPointF> vector)
{
    QPointF pOne = vector[0];
    QPointF pTwo = vector[1];
    QPointF pThree = vector[2];
    double a = distanceFromTwoPoint(pOne,pTwo);
    double b = distanceFromTwoPoint(pTwo,pThree);
    double c = distanceFromTwoPoint(pOne,pThree);

    if(a < 1e-6 || b < 1e-6)
    {
        return 0.0;
    }
    double COSTwo = (a*a + b*b - c*c) / (2*a*b);
    return qRadiansToDegrees(acos(COSTwo)); //  弧度转角度
}

QRectF MathTools::calMarkPosLength(QPointF startPos, QPointF endPos, QRectF validRect, QFont font, QString text, double dScale /*= 1*/)
{
    QFontMetricsF fm(font);
    QRectF textRect(0, 0, fm.width(text), fm.height());

    textRect.setWidth(textRect.width() * dScale);
    textRect.setHeight(textRect.height() * dScale);

    // 偏移量
    double dPadding = 5 * dScale;
    QPointF center = (startPos + endPos) / 2;

    if (qAbs(startPos.x() - endPos.x()) < 1e-3)
    {
        // 垂直状态
        textRect.moveTopLeft(center + QPointF(dPadding, -textRect.height() / 2));
    }
    else if (qAbs(startPos.y() - endPos.y()) < 1e-3)
    {
        // 水平状态
        textRect.moveTopLeft(center - QPointF(textRect.width() / 2, textRect.height() + dPadding));
    }
    else
    {
        // 正切值
        double tanValue = (endPos.y() - startPos.y()) / (endPos.x() - startPos.x());
        if (tanValue > 0)
        {
            // 正切值大于零，直线向上(Qt坐标轴向下)
            if (tanValue > 1)
            {
                textRect.moveBottomLeft(center + QPointF(dPadding, 0));
            }
            else
            {
                textRect.moveBottomLeft(center + QPointF(dPadding, -dPadding));
            }
        }
        else
        {
            // 正切值小于零，直线向下(Qt坐标轴向上)
            if (tanValue < -1)
            {
                textRect.moveTopLeft(center + QPointF(dPadding, 0));
            }
            else
            {
                textRect.moveTopLeft(center + QPointF(dPadding, dPadding));
            }
        }
    }

    if (textRect.top() < validRect.top())
    {
        // 文本上边界超出有效区域(只有tanValue <= 0， 才会出现这种情况)
        textRect.moveTopRight(center + QPointF(-dPadding, dPadding));
    }

    if (textRect.bottom() > validRect.bottom())
    {
        // 文本下边界超出有效区域(只有tanValue > 0， 才会出现这种情况)
        textRect.moveBottomRight(center - QPointF(dPadding, dPadding));
    }

    if (textRect.right() > validRect.right())
    {
        if (center.y() > textRect.top())
        {
            textRect.moveTopRight(center + QPointF(-dPadding, dPadding));
        }
        else
        {
            textRect.moveBottomRight(center - QPointF(dPadding, dPadding));
        }
    }
    return textRect;
}

QRectF MathTools::calMarkPosAngle(QPointF p1, QPointF p2, QPointF p3, QRectF validRect, QFont font, QString text, double dScale)
{
    QFontMetricsF fm(font);
    QRectF textRect(0, 0, fm.width(text), fm.height());

    textRect.setWidth(textRect.width() * dScale);
    textRect.setHeight(textRect.height() * dScale);

    if (p2 == p3)
    {
        textRect.moveTopLeft(QPointF(p2.x() + 5 * dScale, p2.y() - textRect.height() / 2));
        return textRect;
    }

    double deltaX = 5 * dScale;
    double deltaY = textRect.height();

    double y1 = p2.ry() - p1.ry();
    double y2 = p2.ry() - p3.ry();
    if (y1 * y2 < 0)
    {
        deltaY = textRect.height() / 2 - 2 * dScale;
    }
    else if (y1 < 0 && y2 < 0)
    {
        deltaY = -textRect.height() / 2;
    }

    double x1 = p2.rx() - p1.rx();
    double x2 = p2.rx() - p3.rx();
    if (x1 * x2 < 0)
    {
        deltaX = -textRect.width() / 2;
    }
    else if (x1 < 0 && x2 < 0)
    {
        deltaX = -textRect.width() - 8 * dScale;
        deltaY = textRect.height() / 2 - 2 * dScale;
    }
    else if (x1 > 0 && x2 > 0)
    {
        deltaY = textRect.height() / 2 - 2 * dScale;
    }

    // 两条线跨对角象限的情况
    if (x1 * x2 < 0 && y1 * y2 < 0)
    {
        int quadrant = 1;       // 象限
        QPointF angleP1 = getAngleByTwoPoint(p1, p2);
        QPointF angleP3 = getAngleByTwoPoint(p3, p2);

        if (p1.rx() > p2.rx())       // 如果 p1 在右
        {
            if (p1.ry() > p2.ry())
            {
                if (angleP1.rx() > angleP3.rx())
                {
                    // 一象限
                    quadrant = 1;
                }
                else
                {
                    // 三象限
                    quadrant = 3;
                }
            }
            else
            {
                if (angleP1.rx() > angleP3.rx())
                {
                    // 四象限
                    quadrant = 4;
                }
                else
                {
                    // 二象限
                    quadrant = 2;
                }
            }
        }
        else
        {
            if (p1.ry() > p2.ry())
            {
                if (angleP1.rx() > angleP3.rx())
                {
                    // 二象限
                    quadrant = 2;
                }
                else
                {
                    // 四象限
                    quadrant = 4;
                }
            }
            else
            {
                if (angleP1.rx() > angleP3.rx())
                {
                    // 三象限
                    quadrant = 3;
                }
                else
                {
                    // 一象限
                    quadrant = 1;
                }
            }
        }

        switch (quadrant) {
        case 1:
            deltaX = 5 * dScale;
            deltaY = -textRect.height() / 2;
            break;
        case 2:
            deltaX = -textRect.width() - 4 * dScale;
            deltaY = -textRect.height() / 2;
            break;
        case 3:
            deltaX = -textRect.width() - 4 * dScale;
            deltaY = textRect.height();
            break;
        case 4:
            deltaX = 5 * dScale;
            deltaY = textRect.height();
            break;
        default:
            break;
        }
    }
    QPointF textPos = QPointF(p2.rx() + deltaX, p2.ry() + deltaY);
    textRect.moveTopLeft(textPos - QPointF(0, textRect.height() - fm.leading() - fm.descent()));
    return textRect;
}

QPointF MathTools::getAngleByTwoPoint(QPointF p1, QPointF p2)
{
    double _x = 0;
    double _y = 0;

    QPointF px = QPointF(p1.rx(), p2.ry());     // x轴映射点
    QPointF py = QPointF(p2.rx(), p1.ry());     // y轴映射点

    double a = distanceFromTwoPoint(p1, p2);
    double b = distanceFromTwoPoint(p2, px);
    double c = distanceFromTwoPoint(p1, px);

    if(a < 1e-6 || b < 1e-6)
    {
        _x = 0;
    }
    else
    {
        double COSTwo = (a*a + b*b - c*c) / (2*a*b);
        _x = qRadiansToDegrees(acos(COSTwo)); //  弧度转角度
    }

    b = distanceFromTwoPoint(p2, py);
    c = distanceFromTwoPoint(p1, py);
    if(a < 1e-6 || b < 1e-6)
    {
        _y = 0;
    }
    else
    {
        double COSTwo = (a*a + b*b - c*c) / (2*a*b);
        _y = qRadiansToDegrees(acos(COSTwo)); //  弧度转角度
    }
    return QPointF(_x, _y);
}

QVector<QPointF> MathTools::getParallelLinesByVector(const QVector<QPointF> vector)
{
    QVector<QPointF> dstVector;

    if(vector.size() == 3)
    {
        QPointF p1 = vector[0];
        QPointF p2 = vector[1];
        QPointF p3 = vector[2];
        QPointF p11 = p1;
        QPointF p22 = p2;

        if(qAbs(p1.rx() - p2.rx()) < 1e-6)
        {
            // 0. 如果p1、p2是y轴平行线
            p11 = QPointF(p3.rx(), p1.ry());
            p22 = QPointF(p3.rx(), p2.ry());
        }
        else
        {
            //1. 计算 p1和p2的直线方程      y = kx + b1
            double k = (p2.ry() - p1.ry()) / (p2.rx() - p1.rx());

            if(qAbs(k) > 1e-6)
            {
                //double b1 = p1.ry() - k * p1.rx();
                //2. 计算 p3 的平行线方程       y = kx + b2
                double b2 = p3.ry() - k * p3.rx();
                //3. 计算过点 p2和 p1和p2直线的正交直线方程  y = - x/k + b22
                double b22 = p2.ry() + p2.rx()/k;
                //4. 计算过点 p1和 p1和p2直线的正交直线方程  y = - x/k + b11
                double b11 = p1.ry() + p1.rx()/k;
                // 计算3和2的交点
                double _x22 = (b22 - b2)/(k + 1.0/k);
                double _y22 = k * _x22 + b2;
                // 计算4和2的交点
                double _x11 = (b11 - b2)/(k + 1.0/k);
                double _y11 = k * _x11 + b2;
                p11 = QPointF(_x11, _y11);
                p22 = QPointF(_x22, _y22);
            }
            else
            {
                // 如果p1、p2是x轴平行线
                p11 = QPointF(p1.rx(), p3.ry());
                p22 = QPointF(p2.rx(), p3.ry());
            }
        }

        dstVector << p1 << p2 << p11 << p22;
    }
    return dstVector;
}


QVector<double> MathTools::getNumListFromStr(const QString& str)
{
    QRegExp rx("-?[1-9]\\d*\\.\\d*|0+.[0-9]+|-?0\\.\\d*[1-9]\\d*|-?\\d+");
    int pos = 0;
    QVector<double> v;
    while ((pos = rx.indexIn(str, pos)) != -1)
    {
        pos += rx.matchedLength();
        v.push_back(rx.cap(0).toDouble());
    }
    return v;

}

END_NAMESPACE_CIQTEK

